package com.zhudi.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zhudi.model.enums.ErrorCode;
import com.zhudi.model.enums.TeamStatusEnum;
import com.zhudi.expection.BusinessException;
import com.zhudi.mapper.UserTeamMapper;
import com.zhudi.model.entity.Team;
import com.zhudi.model.entity.User;
import com.zhudi.model.entity.UserTeam;
import com.zhudi.model.request.TeamSearchRequest;
import com.zhudi.model.request.TeamUpdateRequest;
import com.zhudi.model.vo.TeamVO;
import com.zhudi.service.TeamService;
import com.zhudi.mapper.TeamMapper;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.zhudi.contant.TeamContant.*;
import static com.zhudi.model.enums.TeamStatusEnum.ENCRYPTION;
import static com.zhudi.model.enums.TeamStatusEnum.PRIVATE;

/**
* @author 朱朱朱朱蒂
* @description 针对表【team(队伍表)】的数据库操作Service实现
* @createDate 2024-03-23 22:52:41
*/
@Service
public class TeamServiceImpl extends ServiceImpl<TeamMapper, Team>
    implements TeamService{



    @Resource
    private TeamMapper teamMapper;

    @Resource
    private UserTeamMapper userTeamMapper;

    @Resource
    private RedissonClient redissonClient;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public long addTeam(Team team) {
        //  1. 传入参数是否为空
        if(team==null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        //2. 是否登录
        //这里是否登录只做id判断，其余信息好像不是很重要
        Long loginUserId = team.getLeaderId();
        if (loginUserId<=0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"用户信息不合法");
        }

        //3. 对队伍参数的合法性检验
        if(!this.isLegalTeam(team)){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"队伍信息设置有误");
        }
        String userLock = String.format("partnerMacth:Team:addTeamLock:%d", loginUserId);
        RLock lock = redissonClient.getLock(userLock);
        try {
            //如果加锁成功了，那么就判断
            if(lock.tryLock(3, TimeUnit.SECONDS)){
                QueryWrapper<UserTeam> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("user_id",loginUserId);
                long userTeamNums = userTeamMapper.selectCount(queryWrapper);
                if (userTeamNums>MAX_TEAM_CREATE_NUM){
                    throw new BusinessException(ErrorCode.USER_ERROR,"用户加入队伍数不能超过5个");
                }

                //5. 插入数据（要加事务）
                team.setPlayersNum(1);
                //	1. 更新队伍表
                boolean save = this.save(team);
                if(!save){
                    throw new BusinessException(ErrorCode.SYSTEM_ERROR);
                }
                //	2. 拿到队伍id
                Long teamId = team.getId();
                //	3. 更新队员-队伍表
                UserTeam userTeam =new UserTeam();
                userTeam.setUserId(loginUserId);
                userTeam.setTeamId(teamId);
                userTeam.setIsDelete(0);
                userTeamMapper.insert(userTeam);

                return teamId;
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            //以防万一，手动解锁
            if(lock.isHeldByCurrentThread()){
                System.out.println("unLock: " + Thread.currentThread().getId());
                lock.unlock();
            }
        }

        //如果没抢锁成功，那么就代表添加失败？
       return 0;
    }


    @Override
    public boolean isLegalTeam(Team team) {
        //  1. 传入参数是否为空
        if(team==null){
            return false;
        }
        //	1. 名称不能为空且长度小于 64（ todo 后续可以加上非法字符检验）
        String name = team.getName();
        if(name==null||name.length()>=64){
            return false;
        }
        //	2. 描述，长度不能超过 512（同样非法字符检验）
        String description = team.getDescription();
        if(description!=null&&description.length()>512){
            return false;
        }
        //	3. 最大人数不能超过 10 个，并且不能小于当前的队伍人数
        Integer playersNum = team.getPlayersNum();


        Integer maxNum = team.getMaxNum();

        //如果两个参数有一个为空，那么我们就判断是非法的
        if(playersNum == null || maxNum == null){
            return false;
        }
        //都不为空的话，则maxNum不能小于playersNum

        if(maxNum>MAX_TEAM_PEOPLE_NUM||maxNum<playersNum){
            return false;
        }
        //	4. 结束时间大于当前时间
        Date expired = team.getExpired();
        if (expired!=null&&new Date().after(expired)){
            return false;
        }
        //	5. 队伍状态如果是加密的话，密码不能为空且长度不能超过 32 位
        //
        TeamStatusEnum teamTeamStatusEnum = TeamStatusEnum.getSatus(team.getStatus());
        //如果队伍状态不在设定的那几个状态里，那么就会返回空
        if(teamTeamStatusEnum==null){
            return false;
        }
        if (teamTeamStatusEnum ==ENCRYPTION){
            String password = team.getPassword();
            return password != null && password.length() <= PASSWORD_MAX_LENGTH;
        }
        return true;
    }

    @Override
    public Page<TeamVO> searchTeamsByPage(TeamSearchRequest teamSearchRequest, User loginUser) {
        // 1. 参数判空、如果为空则抛异常
        if (teamSearchRequest==null||loginUser==null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        //2. 如果页数页码都为空，则默认传输第一页的 10 条信息
        int pageNum = teamSearchRequest.getPageNum();
        int pageSize = teamSearchRequest.getPageSize();
        if(pageNum<=0||pageSize<=0){
            pageNum=1;
            pageSize=10;
        }

        //3. 否则的话就一个个拿去过滤。
        QueryWrapper<Team> queryWrapper = new QueryWrapper<>();
        Long loginUserId = loginUser.getId();

//        Date expired = teamSearchRequest.getExpired();
//        if (expired!=null){
//            queryWrapper.eq("expired",expired);
//        }


        String searchText = teamSearchRequest.getSearchText();
        if (StringUtils.isNotBlank(searchText)) {
            queryWrapper.and(qw -> qw.like("name", searchText).or().like("description", searchText));
        }

//        int maxNum = teamSearchRequest.getMaxNum();
//        // 查询最大人数相等的
//        if ( maxNum > 0) {
//            queryWrapper.eq("max_num", maxNum);
//        }

        // 根据状态来查询
        Integer status = teamSearchRequest.getStatus();
        //判断用户是否是管理员
        boolean admin = loginUser.getRole()==1;

        //如果不等于空，说明要查找某一种状态的队伍
        if (status!=null){
            //先匹配要查找哪一种状态
            TeamStatusEnum statusEnum = TeamStatusEnum.getSatus(status);
            //如果找不到，说明乱传的status，那么默认只查看公开的队伍
            if (statusEnum == null) {
                statusEnum = TeamStatusEnum.PUBLIC;
            }
            //如果有匹配的，无非三种状态：公开、私密、加密

            //如果不是管理员并且要查看私密队伍，那么只能查看自身加入的私密队伍
            if(!admin&&PRIVATE.equals(statusEnum)){

                //获取自身加入的队伍的id列表
                QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();
                userTeamQueryWrapper.eq("user_id",loginUserId);
                Set<Long> joinedTeamId = userTeamMapper.selectList(userTeamQueryWrapper).stream().map(UserTeam::getTeamId).collect(Collectors.toSet());
                //过滤掉那些自己没有加入的
                queryWrapper.eq("status",status).in("id",joinedTeamId);

            //否则的话，可以随便看。
            }else {

                queryWrapper.eq("status",status);

            }

//        如果状态为空，说明要查找所有状态的队伍
//        如果不是管理员，那么对于那些私密队伍，只能查看自己加入的
        }else if(!admin){
            //获取自身加入的队伍的id列表
            QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();
            userTeamQueryWrapper.eq("user_id",loginUserId);
            Set<Long> joinedTeamId = userTeamMapper.selectList(userTeamQueryWrapper).stream().map(UserTeam::getTeamId).collect(Collectors.toSet());
            //过滤掉那些自己没有加入的私密队伍
            queryWrapper.not(i -> i.eq("status", 2).notIn("id", joinedTeamId));
        }


        //按照leaderId查询
        Long leaderId = teamSearchRequest.getLeaderId();
        //如果不为空且合法，说明要找领队是xx的队伍
        if (leaderId!=null&&leaderId>=0){
            queryWrapper.eq("leader_id",leaderId);
        }

        // 获取查询结果
        Page<Team> teamPage = teamMapper.selectPage(new Page<>(pageNum, pageSize), queryWrapper);

        //接下来需要将Team转为TeamVO
        //其中有一个isJoin字段需要我们判断当前用户是否加入。
        //所以先获取当前用户加入的队伍id，然后去判断有没有就行了。

        QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();
        userTeamQueryWrapper.eq("user_id",loginUserId);
        //获取用户加入的队伍idSet
        Set<Long> userJoinTeamIdSet = userTeamMapper.selectList(userTeamQueryWrapper).stream().map(UserTeam::getTeamId)
                .collect(Collectors.toSet());


        Page<TeamVO> teamVOResult = new Page<>();
        BeanUtils.copyProperties(teamPage,teamVOResult);
        // 将Page<Team>转换为Page<TeamVO>
        List<TeamVO> teamVOList = teamPage.getRecords().stream()
                .map(team -> {
                    TeamVO teamVO = new TeamVO();
                    //如果有加入则设为true
                    teamVO.setJoin(userJoinTeamIdSet.contains(team.getId()));
                    BeanUtils.copyProperties(team, teamVO);
                    return teamVO;
                })
                .collect(Collectors.toList());

        teamVOResult.setRecords(teamVOList);


        return teamVOResult;


    }

    @Override
    public boolean updateTeam(TeamUpdateRequest teamUpdateRequest) {
        if(teamUpdateRequest==null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"更新参数为空");
        }
        //我们首先需要确认是否存在要更新的队伍，如果不存在可以返回null，

        // 如果存在的话，我们要拿到其成员人数，因为等下要和maxNum作比较
        Long teamId = teamUpdateRequest.getId();
        if (teamId==null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"缺少要更新的队伍id");
        }

        Team DBTeam = teamMapper.selectById(teamId);
        //如果为空表示id有误
        if (DBTeam==null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"不存在要更新的队伍");
        }
        Integer playersNum = DBTeam.getPlayersNum();
        //创建一个新的team来更新信息
        Team newTeam = new Team();
        newTeam.setPlayersNum(playersNum);
        BeanUtils.copyProperties(teamUpdateRequest,newTeam);
        //因为需要检查
        //校验要更改的信息是否合法

        boolean legalTeam = this.isLegalTeam(newTeam);
        if(!legalTeam){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"队伍信息设置有误");
        }
        //如果队伍状态是不加密的，那么强制设置密码为空
        TeamStatusEnum teamStatusEnum = TeamStatusEnum.getSatus(newTeam.getStatus());
        if (!ENCRYPTION.equals(teamStatusEnum)){
            newTeam.setPassword("");
        }
        //注意，如果有哪一个参数不想修改，应该是传入原来的值，而不是什么都不传，否则会视为要置空
        //因为不想前端传回team当前队伍的人数，以防被更改导致出错，而更新的话又需要数值，否则会置为0
        //所以需要

        return teamMapper.updateById(newTeam)>=1;
    }

    @Override
    public List<TeamVO> getMyJoinTeam(User loginUser) {
        if(loginUser==null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Long loginUserId = loginUser.getId();
        QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();
        userTeamQueryWrapper.eq("user_id",loginUserId);
        //获取用户加入的队伍的UserTeam对象
        List<UserTeam> userTeams = userTeamMapper.selectList(userTeamQueryWrapper);
        //获取队伍id列表
        List<Long> teamIdList = userTeams.stream().map(UserTeam::getTeamId).collect(Collectors.toList());
        //根据列表去获取对应的队伍信息，并且转为VO类
        //保存结果的list
        List<TeamVO> result = new ArrayList<>();
        for (Long teamId : teamIdList) {
            Team team = teamMapper.selectById(teamId);
            TeamVO teamVO = new TeamVO();
            BeanUtils.copyProperties(team,teamVO);
            result.add(teamVO);
        }
        return result;
    }


}




